<?xml version="1.0" encoding="UTF-8"?><d:tdl xmlns="http://www.w3.org/1999/xhtml" xmlns:bb="http://www.backbase.com/2006/client"  xmlns:d="http://www.backbase.com/2006/tdl"  xmlns:bf="http://www.backbase.com/2007/forms">

	<d:namespace name="http://www.backbase.com/2007/forms">

		<d:uses interface="iValidationForm iInput iValidationRequired iValidationSchema iInputList iOption iMessenger" src="forms.xml"/>

		<d:resource type="text/javascript"><![CDATA[
			if (!window.BBForms)
				BBForms = {};
			BBForms.namespaceURI = 'http://www.backbase.com/2007/forms';
		]]></d:resource>

		<d:element name="messengerBase" implements="bf:iMessenger" abstract="true">
			
			<d:attribute name="bf:messagesRef">
				
			</d:attribute>
			<d:property name="messages">
				<d:getter type="text/javascript"><![CDATA[
					if (this.hasAttributeNS(BBForms.namespaceURI, 'messagesRef'))
						var xpath = this.getAttributeNS(BBForms.namespaceURI, 'messagesRef');
					else
						return null;
					var messages = bb.evaluateSmart(xpath, this, this);
					if (!messages) {
						bb.command.trace(this, 'Unable to resolve messagesRef XPath to a node.', 2);
						return null;
					}
					return messages;
				]]></d:getter>
			</d:property>
			<d:handler event="valid" type="text/javascript"><![CDATA[
				if (event.target == this) {
					var messages = this.getProperty('messages');
					if (messages)
						messages.handleValidityChanged(event);
				}
			]]></d:handler>
			<d:handler event="invalid" type="text/javascript"><![CDATA[
				if (event.target == this) {
					var messages = this.getProperty('messages');
					if (messages)
						messages.handleValidityChanged(event);
				}
			]]></d:handler>
		</d:element>

		<d:element name="formBase" extends="bf:messengerBase" abstract="true" implements="bf:iValidationForm">
			

			<d:attribute name="bf:destination">
				
			</d:attribute>

			<d:attribute name="bf:mode">
				
			</d:attribute>

			<d:property name="elements">
				
				<d:getter type="text/javascript"><![CDATA[
					var aElements = this.viewNode.elements;
					var aElementsReturn = [];
					for (var i = 0, iMax = aElements.length; iMax > i ; i++) {
						var oController = bb.getControllerFromView(aElements[i]);
						if (bb.instanceOf(oController, BBForms.namespaceURI, 'iInput')) {
							// don't add nodes that are already in the list
							for (var j = aElementsReturn.length - 1; j >= 0; j--)
								if (aElementsReturn[j] == oController)
									break;
							if (j < 0)
								aElementsReturn[aElementsReturn.length] = oController;
						}
					}
					return aElementsReturn;
				]]></d:getter>
			</d:property>

			<d:property name="dataSet">
				<d:getter type="text/javascript"><![CDATA[
					var elements = this.getProperty('elements');
					var dataset = [];
					for (var i=0; i < elements.length; i++) {
						if (elements[i].getProperty('successful')) {
							if (elements[i].instanceOf(BBForms.namespaceURI, 'iInputMultiple')
									&& elements[i].getProperty('multiple')) {
								var options = elements[i].getProperty('options');
								for (var j=0; j < options.length; j++) {
									if(options[j].getProperty('successful'))
										dataset[dataset.length] = [elements[i].getProperty('name'), options[j].getProperty('value')];
								}
							} else if (elements[i].instanceOf(BBForms.namespaceURI, 'iFileInput')) {
								// do nothing
							} else {
								dataset[dataset.length] = [elements[i].getProperty('name'), elements[i].getProperty('value')];
							}
						}
					}
					return dataset;
				]]></d:getter>
			</d:property>

			<d:property name="encodedData">
				<d:getter type="text/javascript"><![CDATA[
					// TODO: Support other encodings, such as application/x-www-form+xml
					//       See http://www.w3.org/TR/web-forms-2/#x-www-form-xml
					//
					var dataset = this.getProperty('dataSet');
					var encoding = this.getProperty('enctype');
					if (encoding == 'application/x-www-form-urlencoded' ||
							this.getProperty('method') == 'GET') {
						var encodedData = [];
						for (var i=0, fds_length=dataset.length; i < fds_length; i++) {
							encodedData[encodedData.length] = encodeURIComponent(dataset[i][0]) + '=' + encodeURIComponent(dataset[i][1]);
						}
						return encodedData.join('&');
					} else {
						bb.command.trace(this, 'Unsupported encoding: ' + encoding, 2);
						return null;
					}
				]]></d:getter>
			</d:property>

			<d:property name="destination">
				
				<d:getter type="text/javascript"><![CDATA[
					var sDest;
					// Get the destination from the form tag
					if (this.hasAttributeNS(BBForms.namespaceURI, 'destination'))
						sDest = this.getAttributeNS(BBForms.namespaceURI, 'destination');
					else
						return null;
					var context = this;
					var destination = bb.evaluateSmart(sDest, this, this);
					if (!destination) {
						bb.command.trace(this, 'Unable to resolve destination XPath to a node.', 2);
						return null;
					}
					return destination;
				]]></d:getter>
			</d:property>

			<d:property name="mode">
				
				<d:getter type="text/javascript"><![CDATA[
					return this.hasAttributeNS(BBForms.namespaceURI, 'mode') ?
						this.getAttributeNS(BBForms.namespaceURI, 'mode') : 'appendChild';
				]]></d:getter>
			</d:property>

			<d:method name="submit">
				<d:body type="text/javascript"><![CDATA[
					var destination = this.getProperty('destination');
					if (destination) {
						var mode = this.getProperty('mode');
						var data = this.getProperty('encodedData');
						var method = this.getProperty('method');
						var enctype = this.getProperty('enctype');
						if (data != null) {
							var elements = this.getProperty('elements');
							for (var i=0; i < elements.length; i++) {
								if (elements[i].instanceOf(BBForms.namespaceURI, 'iFileInput') &&
									elements[i].getProperty('successful')) {
									elements[i].submit();
								}
							}
							bb.command.load( this.getProperty('action'), method, data,
									method != 'GET' ? {'Content-Type': enctype} : null,
									destination, mode, null, null, null, null, this);
						}
					} else
						this.viewNode.submit();
				]]></d:body>
			</d:method>

			<d:property name="validity">
				
				<d:getter type="text/javascript"><![CDATA[
					var aElements = this.getProperty('elements');
					var validity = true;
					for (var i=0, iMax = aElements.length; i < iMax; i++){
						if (bb.instanceOf(aElements[i], BBForms.namespaceURI, 'iValidation'))
							validity = aElements[i].validate() && validity;
					}
					var event = bb.document.createEvent('CustomEvent');
					event.initCustomEventNS(null, validity ? 'valid' : 'invalid', true, false, 0);
					this.dispatchEvent(event);
					return validity;
				]]></d:getter>
			</d:property>

			<d:method name="validate">
				
				<d:body type="text/javascript"><![CDATA[
					var aElements = this.getProperty('elements');
					var validity = true;
					for (var i=0, iMax = aElements.length; i < iMax; i++){
						if (bb.instanceOf(aElements[i], BBForms.namespaceURI, 'iValidation'))
							validity = aElements[i].validate() && validity;
					}
					var event = bb.document.createEvent('CustomEvent');
					event.initCustomEventNS(null, validity ? 'valid' : 'invalid', true, false, 0);
					this.dispatchEvent(event);
					return validity;
				]]></d:body>
			</d:method>

			<d:method name="validateAndSubmit">
				<d:body type="text/javascript"><![CDATA[
					if(this.validate())
						this.submit();
				]]></d:body>
			</d:method>
		</d:element>

		<d:element name="inputBase" extends="bf:messengerBase" implements="bf:iInput bf:iValidationRequired bf:iValidationSchema" abstract="true">
			

			<d:attribute name="bf:required">
				
			</d:attribute>

			<d:attribute name="bf:dataType">
				
			</d:attribute>

			<d:property name="schemaType">
				<d:getter type="text/javascript"><![CDATA[
					if (this.hasAttributeNS(BBForms.namespaceURI, 'dataType'))
						var sDataType = this.getAttributeNS(BBForms.namespaceURI, 'dataType');
					else
						return null;
					var qnameSplit = sDataType.split(':');
					var type = qnameSplit.pop();
					var prefix = qnameSplit.pop() || null;
					var namespace = this.lookupNamespaceURI(prefix);
					var oType = bb.schema.getType(namespace, type);
					if (!oType)
						bb.command.trace(this, 'Schema type ' + sDataType + ' not found.', 2);
					return oType;
				]]></d:getter>
			</d:property>

			<d:property name="form">
				<d:getter type="text/javascript"><![CDATA[
					var oElm = this;
					while (oElm.getProperty('nodeType') == 1) {
						if (bb.instanceOf(oElm, BBForms.namespaceURI, 'iForm'))
							return oElm;
						oElm = oElm.getProperty('parentNode');
					}
					return null;
				]]></d:getter>
			</d:property>

		 	<d:property name="successful">
		 		<d:getter type="text/javascript"><![CDATA[
		 			return this.getProperty('name') != '' && !this.getProperty('disabled');
		 		]]></d:getter>
	 		</d:property>

			<d:property name="required">
				<d:getter type="text/javascript"><![CDATA[
					var sRequired = this.hasAttributeNS(BBForms.namespaceURI, 'required') ?
							this.getAttributeNS(BBForms.namespaceURI, 'required') : 'default';
					return (sRequired == 'true' || sRequired == 'required') ? 1 : sRequired == 'false' ? 0 : 2;
				]]></d:getter>
			</d:property>

			<d:property name="validity">
				
				<d:getter type="text/javascript"><![CDATA[
					// cache!
					var value = this.getProperty('value');
					if ('forms_value' in this._ && this._.forms_value === value)
						return this._.forms_validity;

					var validity = true;
					var value = this.getProperty('value');
					var detail = 0;
					var required = this.getProperty('required');
					var type = this.getProperty('schemaType');

					if (validity && required == 1) {
						validity = validity && Boolean(value);
						if (!validity) detail = 1;
					}
					// if required == 0 and the value is empty, do not check validity
					if (validity && type && !(required == 0 && !Boolean(value))) {
						validity = validity && bb.schema.validateSimpleType(value, type, this);
						if (!validity) detail = 2;
					}
					this._.forms_validity = validity;
					this._.forms_detail = detail;
					this._.forms_value = value;
					return validity;
				]]></d:getter>
			</d:property>

			<d:method name="validate">
				
				<d:body type="text/javascript"><![CDATA[
					var validity = this.getProperty('validity');
					var event = bb.document.createEvent('CustomEvent');
					var detail = validity || isNaN(this._.forms_detail) ? 0 : this._.forms_detail;

					event.initCustomEventNS(null, validity ? 'valid' : 'invalid', true, false, detail);
					this.dispatchEvent(event);
					return validity;
				]]></d:body>
			</d:method>
		</d:element>

		<d:element name="inputListBase" extends="bf:inputBase" implements="bf:iInputList" abstract="true">
			

			<d:property name="options">
				
				<d:getter type="text/javascript"><![CDATA[
					var aChildren = this.getProperty('childNodes');
					var aReturn = [];

					for ( var i = 0, iMax = aChildren.length ; iMax > i ; i++ ){
						if (aChildren[i] && bb.instanceOf(aChildren[i], BBForms.namespaceURI, 'iOption'))
							aReturn[aReturn.length] = aChildren[i];
					}
					return aReturn;
				]]></d:getter>
			</d:property>

			<d:property name="successful">
				<d:getter type="text/javascript"><![CDATA[
					var aOptions = this.getProperty('options');
					var bOptionSelected = false;

					for ( var i = 0, iMax = aOptions.length ; iMax > i ; i++ ){
						bOptionSelected = aOptions[i].getProperty('selected');

						if(bOptionSelected)
							break;
					}

					return this.getProperty('name') != '' && bOptionSelected && !this.getProperty('disabled');
				]]></d:getter>
			</d:property>
		</d:element>

		<d:element name="optionBase" implements="bf:iOption" abstract="true">
			

			<d:property name="successful">
				<d:getter type="text/javascript"><![CDATA[
					return this.getProperty('selected') && !this.getProperty('disabled');
				]]></d:getter>
			</d:property>
		</d:element>

	</d:namespace>
</d:tdl>